package com.pocket.insight.base.sql.dialect;

import com.pocket.insight.base.exception.SysException;
import com.pocket.insight.base.mql.TypedVal;
import com.pocket.insight.base.sql.Dialect;
import com.pocket.insight.base.utils.SqlUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 描述：
 *
 * @author shuize
 * @create 2024/11/30
 */
@Slf4j
public abstract class BaseDialect implements Dialect<String> {

    protected boolean doQuote      = true;
    protected long    majorVersion = 0L;
    protected long    minorVersion = 0L;
    protected String  databaseProductVersion;
    protected String  databaseProductName;

    /********************************* 1. 标识符差异配置 *********************************/
    @Override
    public String escString(String s) {
        return StringUtils.replace(s, "'", "''");
    }

    @Override
    public String getRightQuoteChar() {
        return getLeftQuoteChar();
    }

    public String quoteString(String s) {
        return String.format("'%s'", this.escString(s));
    }

    @Override
    public String quotePath(List<String> path) {
        return Optional.ofNullable(path).orElse(List.of()).stream().map(this::quotePathName).collect(Collectors.joining("."));
    }

    @Override
    public String quotePathName(String pathName) {
        return quoteSingleWithCheck(pathName);
    }

    @Override
    public String quoteTableName(String tableName) {
        if (tableName == null) {
            return quoteSingleWithCheck(null);
        }
        return quoteEntity(tableName);
    }

    @Override
    public String quoteTableNameWithoutSplit(String tableName) {
        return this.quoteSingleWithCheck(tableName);
    }

    @Override
    public String quoteFieldName(String fieldName) {
        return quoteSingleWithCheck(fieldName);
    }

    @Override
    public String quoteFieldName(String tableName, String fieldName, String baseTableAlias) {
        return StringUtils.isBlank(tableName) ? quoteFieldName(fieldName) : quoteTableName(tableName) + "." + quoteTableName(tableName);
    }

    @Override
    public String quoteEntity(String entity) {
        ArrayList<String> parts = new ArrayList<>();
        for (String part : StringUtils.split(entity, ".", getMaxEntityDepth())) {
            parts.add(quoteSingleWithCheck(part));
        }
        return StringUtils.join(parts, '.');
    }

    @Override
    public String unquoteSingleEntity(String s) {
        return SqlUtil.removeRepeatedSymbolAtHeadAndTail(s, '"');
    }

    @Override
    public String quoteAliasName(String aliasName) {
        return quoteFieldName(aliasName);
    }

    @Override
    public String quoteOrderByAliasName(TypedVal val) {
        return this.quoteAliasName(val.getAlias());
    }

    @Override
    public String quoteGroupByFieldName(TypedVal val) {
        return val.getStr();
    }

    protected String quoteSingleOrNot(String entity) {
        return !this.doQuote ? entity :quoteSingle(entity);
    }

    protected String quoteSingle(String entity) {
        return String.format("%s%s%s", getLeftQuoteChar(), entity, getRightQuoteChar());
    }


























    @Override
    public TypedVal reformCustomQuery(String customQuery) {
        return new TypedVal(bracketCustomSql(customQuery));
    }

    @Override
    public TypedVal createTableVal(List<String> tablePath) {
        return new TypedVal(this.quotePath(tablePath));
    }

    public static String bracketCustomSql(String sql) {
        for(sql = sql.trim(); sql.endsWith(";"); sql = sql.trim()) {
            sql = sql.substring(0, sql.length() - 1);
        }

        return sql.startsWith("(") ? sql : "(" + sql + ")";
    }

    @Override
    public Dialect setDoQuote(boolean doQuote) {
        this.doQuote = doQuote;
        return this;
    }

    /******************************* 数据库差异配置 *********************************/


    protected int getIdentifierMaxLength() {
        return Integer.MAX_VALUE;
    }

    protected String quoteSingleWithCheck(String entity) {
        validateIdentifier(entity);
        return quoteSingleOrNot(entity);
    }

    public void validateIdentifier(String identifier) {
        if (identifier != null && identifier.length() > getIdentifierMaxLength()) {
            log.error("identifier: " + identifier);
            throw new SysException("ERROR_IDENTIFIER_IS_TOO_LONG");
        }
    }

    @Override
    public boolean isAliasAmbiguousInJoin() {
        return false;
    }

    @Override
    public boolean isOffsetLimitRequiresOrderBy() {
        return false;
    }

    @Override
    public String nullsOrder(String sortStr, String direction, String nullsOrder) {
        return sortStr + direction;
    }

    @Override
    public String nullsOrder(String sortStr, String direction, TypedVal.EvalScope scope, String nullsOrder) {
        return this.nullsOrder(sortStr, direction, nullsOrder);
    }


    /********************************* 数据库版本信息【conn-version-info】 *********************************/
    @Override
    public Dialect setVersion(long majorVersion, long minorVersion) {
        this.majorVersion = majorVersion;
        this.minorVersion = minorVersion;
        return this;
    }

    @Override
    public long getMajorVersion() {
        return this.majorVersion;
    }

    @Override
    public long getMinorVersion(){
            return this.minorVersion;
    }

    @Override
    public Dialect setDbProVersion(String dbProVersion){
        this.databaseProductVersion = dbProVersion;
        return this;
    }

    @Override
    public String getDbProVersion(){
        return this.databaseProductVersion;
    }

    @Override
    public Dialect setDbProName(String dbProName){
        this.databaseProductName = dbProName;
        return this;
    }

    @Override
    public String getDbProName(){
        return this.databaseProductName;
    }

    /********************************* SQL 语句构建 *********************************/

    @Override
    public String fieldAsAlias(String field, String alias) {
        return field + " AS " + alias;
    }



    protected int getMaxEntityDepth() {
        return 2;
    }





    @Override
    public String getEmptyTable() {
        return "";
    }

    /*********************************  *********************************/
    @Override
    public boolean isBoolAvailable() {
        return true;
    }

    @Override
    public String boolToSqlLiteral(Boolean value) {
        return value.toString().toUpperCase();
    }

    @Override
    public boolean isJsonAvailable() {
        return false;
    }

    public Object jodaToNativeDisplayFormat(String jodaFormat) {
        return this.jodaToNativeParseFormat(jodaFormat);
    }

}
